﻿using System;
using System.IO;
using System.Text;
using System.Threading;
using WinAPI32Library;

namespace AnonymousPipes
{
    class Program
    {
        static void Main(string[] args)
        {
            // ----------------------- 
            //       Create pipe
            // -----------------------

            Console.WriteLine(double.MaxValue);
            Console.WriteLine(double.MinValue);


            // handles
            IntPtr hReadPipe, hWritePipe, hInheritWritePipe;
            // security attributes
            Kernel32.SECURITY_ATTRIBUTES sa = new Kernel32.SECURITY_ATTRIBUTES();
            // inherit handle we must 
            sa.bInheritHandle = true;
            // create pipe
            bool pipeIsCreated = Kernel32.CreatePipe(out hReadPipe, out hWritePipe, ref sa, 0);
            // check if created pipe has been
            Console.WriteLine("Pipe created: " + pipeIsCreated);
            // try to duplicate handle
            bool handleIsDuplicated = Kernel32.DuplicateHandle(Kernel32.GetCurrentProcess(), hWritePipe, Kernel32.GetCurrentProcess(), out hInheritWritePipe, 0, true, (uint)Kernel32.DuplicateOptions.DUPLICATE_SAME_ACCESS);
            // check this
            Console.WriteLine("Handle duplicated: " + handleIsDuplicated);
            // close unnecessary handle
            Kernel32.CloseHandle(hWritePipe);

            // ----------------------- 
            //       Create process
            // -----------------------

            int processesNumber = 4;
            while (true)
            {
                Console.Write("Input x: ");
                string input = Console.ReadLine();
                NativeOverlapped ol = new NativeOverlapped();
                // bytes to write
                uint bw = 0;
                // if exit
                if (input == "exit" || input == "")
                    break;
                // startup info 
                Kernel32.STARTUP_INFO si = new Kernel32.STARTUP_INFO();
                // process information
                Kernel32.PROCESS_INFORMATION pi = new Kernel32.PROCESS_INFORMATION();
                for (int i = 0; i < processesNumber; i++)
                {
                    // create process
                    bool processIsCreated = Kernel32.CreateProcess(
                        null,
                        @"D:\MSVSProjects\Erofeev TFS\AnonymousPipesClient\bin\Debug\AnonymousPipesClient.exe " + (int)hInheritWritePipe + " " + (int)hReadPipe + " " + i,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        true,
                        (uint)Kernel32.CreationFlags.CREATE_NO_WINDOW,
                        IntPtr.Zero,
                        null,
                        ref si,
                        out pi);
                    Console.WriteLine("Process created: " + processIsCreated);
                    // close process and thread handles
                    Kernel32.CloseHandle(pi.hProcess);
                    Kernel32.CloseHandle(pi.hThread);

                    // wait while tread inits its pipe
                    // read data from pipe
                    byte[] b = new byte[150];
                    // bytes read
                    uint br = 0;
                    // data string
                    string dataRead = "";
                    // read pipe
                    Kernel32.ReadFile(hReadPipe, b, 150, out br, ref ol);
                    // convert bytes to string
                    dataRead = new UTF8Encoding().GetString(b, 0, (int)br).Trim();
                    // if pipe is not ready GTH
                    if (dataRead != "ready")
                        return;

                    // convert string to bytes
                    byte[] bStr = new UTF8Encoding().GetBytes(input);
                    // write data to pipe
                    Kernel32.WriteFile(hInheritWritePipe, bStr, (uint)bStr.Length, out bw, ref ol);
                    // read data from pipe
                    b = new byte[150];
                    // bytes read
                    br = 0;
                    // data string
                    dataRead = "";
                    // read pipe
                    Kernel32.ReadFile(hReadPipe, b, 150, out br, ref ol);
                    // convert bytes to string
                    dataRead = new UTF8Encoding().GetString(b, 0, (int)br).Trim();
                    Console.WriteLine("Data recieved: " + dataRead);
                    WriteLog(input, dataRead);
                }
            }
            // close all opened handles
            Kernel32.CloseHandle(hInheritWritePipe);
            Kernel32.CloseHandle(hReadPipe);
        }

        // write log to file
        public static void WriteLog(string x, string d)
        {
            StreamWriter w = new StreamWriter("log.txt", true);
            w.WriteLine("Argument: " + x);
            w.WriteLine(d);
            w.WriteLine();
            w.Close();
        }
    }
}
